package cn.school.attendance.dormitory.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.school.attendance.dormitory.dao.DormitoryAttendanceMapper;
import cn.school.attendance.dormitory.dao.DormitoryStatusMapper;
import cn.school.attendance.dormitory.dao.DormitoryStudentInfoMapper;
import cn.school.attendance.dormitory.entity.DormitoryAttendanceDo;
import cn.school.attendance.dormitory.entity.DormitoryStatusDo;
import cn.school.attendance.dormitory.entity.DormitoryStudentInfo;
import cn.school.attendance.dormitory.enums.DormitoryTypeEnum;
import cn.school.attendance.dormitory.pojo.AttendanceDto;
import cn.school.attendance.dormitory.pojo.QueryParam;
import cn.school.attendance.dormitory.service.DormitoryAttendanceService;
import cn.school.attendance.dormitory.vo.DormitoryAttendanceVo;
import cn.school.attendance.dormitory.vo.StudentAttendanceVO;
import cn.school.basics.dao.BaseSpaceLocationDao;
import cn.school.basics.vo.BaseSpaceLocationVO;
import cn.school.common.api.CommonPage;
import cn.school.common.utils.StringUtils;
import cn.school.common.utils.SysUserUtils;
import com.alibaba.excel.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @className: DormitoryAttendanceServiceImpl
 * @author: Alex
 * @date: 2023/4/1
 **/
@Service
public class DormitoryAttendanceServiceImpl extends ServiceImpl<DormitoryAttendanceMapper, DormitoryAttendanceDo> implements DormitoryAttendanceService {

	@Resource
	private DormitoryStatusMapper dormitoryStatusMapper;

	@Resource
	private DormitoryStudentInfoMapper dormitoryStudentInfoMapper;

	@Resource
	private DormitoryAttendanceMapper dormitoryAttendanceMapper;

	@Override
	public CommonPage<DormitoryStatusDo> findDormitoryAttendanceStatus(BaseSpaceLocationVO vo) {
		IPage<DormitoryStatusDo> iPage = new Page<>();
		// 构造查询时间段参数
		buildQueryTimes(vo);

		iPage.setCurrent(vo.getPageNum());
		iPage.setSize(vo.getPageSize());
		LambdaQueryWrapper<DormitoryStatusDo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(DormitoryStatusDo::getLocationType, "6");
		lambdaQueryWrapper.eq(Objects.nonNull(vo.getLocationPid()), DormitoryStatusDo::getLocationPid, vo.getLocationPid());
		lambdaQueryWrapper.eq(StringUtils.isNotEmpty(vo.getLocationName()), DormitoryStatusDo::getLocationName, vo.getLocationName());
		lambdaQueryWrapper.orderByAsc(DormitoryStatusDo::getId);
		//租户
		lambdaQueryWrapper.eq(DormitoryStatusDo::getTenantId,SysUserUtils.getSysUser().getTenantId());
		// 查找出所有宿舍
		IPage<DormitoryStatusDo> list = dormitoryStatusMapper.getList(lambdaQueryWrapper, iPage);

		if (CollectionUtil.isEmpty(list.getRecords())) {
			return CommonPage.restPage(list);
		}

		List<DormitoryStatusDo> listRecords = list.getRecords();
		List<Long> collect = listRecords.stream().map(DormitoryStatusDo::getId).collect(Collectors.toList());
		LambdaQueryWrapper<DormitoryAttendanceDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.in(DormitoryAttendanceDo::getLocationId, collect);
		queryWrapper.gt(DormitoryAttendanceDo::getCreateTime, vo.getCreateTime());
		queryWrapper.lt(DormitoryAttendanceDo::getCreateTime, vo.getModifyTime());
		//租户
		queryWrapper.eq(DormitoryAttendanceDo::getTenantId,SysUserUtils.getSysUser().getTenantId());
		List<DormitoryAttendanceDo> attendanceDos = dormitoryAttendanceMapper.selectList(queryWrapper);
		Map<Long, List<DormitoryAttendanceDo>> listMap = attendanceDos.stream().collect(Collectors.groupingBy(DormitoryAttendanceDo::getLocationId));

		List<DormitoryStatusDo> records = list.getRecords();
		if (CollectionUtil.isEmpty(records)) {
			return CommonPage.restPage(list);
		}
		// 补全是否全勤信息
		buildAttendanceStatus(listMap, records);
		return CommonPage.restPage(list);
	}

	private void buildQueryTimes(BaseSpaceLocationVO vo) {
		Date dateTime = DateUtil.date();
		if (Objects.nonNull(vo.getCreateTime())) {
			dateTime = vo.getCreateTime();
		}
		try {
			vo.setCreateTime(DateUtils.parseDate(DateUtil.format(dateTime, "yyyy-MM-dd") + " 00:00:00"));
			vo.setModifyTime(DateUtils.parseDate(DateUtil.format(dateTime, "yyyy-MM-dd") + " 23:59:59"));
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}

	private void buildAttendanceStatus(Map<Long, List<DormitoryAttendanceDo>> listMap, List<DormitoryStatusDo> records) {
		for (DormitoryStatusDo record : records) {
			DecimalFormat df = new DecimalFormat("##.##%");
			// 如果该宿舍没有人入住
			if (Objects.isNull(record.getDormitoryCount())
					|| Objects.equals(record.getDormitoryCount(), "0")) {
				record.setDormitoryCount("0");
				record.setAttendanceStatus("1");
				record.setAttendanceRatio("100%");
				record.setLeaveRatio("0%");
				continue;
			}

			// 该宿舍在某个时间段没有考勤记录
			List<DormitoryAttendanceDo> doList = listMap.get(record.getId());
			if (CollectionUtil.isEmpty(doList)) {
				record.setStatusDoList(new ArrayList<>());
				record.setAttendanceStatus("0");
				record.setAttendanceRatio("0%");
				record.setLeaveRatio("0%");
				continue;
			}
			record.setStatusDoList(doList);
			record.setAttendanceStatus("1");
			// 如果有入住学生考勤状态为0,则该宿舍为非全勤
			if (record.getStatusDoList().size() != Integer.parseInt(record.getDormitoryCount()) ||
					record.getStatusDoList().stream().anyMatch(dormitoryAttendanceDo -> dormitoryAttendanceDo.getStatus().equals("0"))) {
				record.setAttendanceStatus("0");
			}
			// 设置考勤百分比
			long attendanceCount = doList.stream().filter(att -> Objects.equals(att.getStatus(), "1")).count();
			long leaveCount = doList.stream().filter(att -> Objects.equals(att.getStatus(), "2")).count();
			record.setNormalCount(attendanceCount);
			record.setLeaveCount(leaveCount);
			record.setAttendanceRatio(df.format((double) attendanceCount/ Double.parseDouble(record.getDormitoryCount())));
			record.setLeaveRatio(df.format((double) leaveCount/ Double.parseDouble(record.getDormitoryCount())));
		}
	}

	@Override
	public List<DormitoryStudentInfo> getDormitoryStudentInfos(BaseSpaceLocationVO vo) {
		// 查询宿舍人数
		LambdaQueryWrapper<DormitoryStudentInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(DormitoryStudentInfo::getLocationId, vo.getId());
		lambdaQueryWrapper.isNotNull(DormitoryStudentInfo::getStudentId);
		List<DormitoryStudentInfo> dormitoryStudentInfos = dormitoryStudentInfoMapper.selectList(lambdaQueryWrapper);
		if (CollectionUtil.isEmpty(dormitoryStudentInfos)) {
			return Collections.emptyList();
		}
		// 构造查询时间段
		buildQueryTimes(vo);

		// 匹配考勤状态，没有则为缺勤
		List<Long> collect = dormitoryStudentInfos.stream().map(DormitoryStudentInfo::getStudentId).collect(Collectors.toList());
		LambdaQueryWrapper<DormitoryAttendanceDo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.in(DormitoryAttendanceDo::getStudentId, collect);
		queryWrapper.gt(DormitoryAttendanceDo::getCreateTime, vo.getCreateTime());
		queryWrapper.lt(DormitoryAttendanceDo::getCreateTime, vo.getModifyTime());
		List<DormitoryAttendanceDo> attendanceDos = dormitoryAttendanceMapper.selectList(queryWrapper);

		for (DormitoryStudentInfo studentInfo : dormitoryStudentInfos) {
			studentInfo.setStatus("0");
			studentInfo.setIsNormal("1");
			// 如果考勤表中有记录
			attendanceDos.stream().filter(dormitoryAttendanceDo -> dormitoryAttendanceDo.getStudentId().equals(studentInfo.getStudentId())).findAny().ifPresent(
					dormitoryAttendanceDo -> {
						studentInfo.setStatus(dormitoryAttendanceDo.getStatus());
						studentInfo.setAttendanceId(dormitoryAttendanceDo.getId());
						studentInfo.setCreateTime(dormitoryAttendanceDo.getCreateTime());
						studentInfo.setCreateBy(dormitoryAttendanceDo.getCreateBy());
						studentInfo.setModifyTime(dormitoryAttendanceDo.getModifyTime());
						studentInfo.setModifyBy(dormitoryAttendanceDo.getModifyBy());
					}
			);
			if (studentInfo.getStatus().equals("0")) {
				studentInfo.setIsNormal("0");
			}
		}
		return dormitoryStudentInfos;
	}

	@Override
	public boolean editAttendanceStatus(List<DormitoryStudentInfo> list) {
		List<DormitoryAttendanceDo> attendanceDos = new ArrayList<>();
		for (DormitoryStudentInfo dormitoryStudentInfo : list) {
			DormitoryAttendanceDo attendanceDo = new DormitoryAttendanceDo();
			// 如果考勤表中有记录
			if (Objects.nonNull(dormitoryStudentInfo.getAttendanceId())) {
				attendanceDo.setId(dormitoryStudentInfo.getAttendanceId());
				attendanceDo.setModifyTime(DateUtil.now());
				attendanceDo.setModifyBy(SysUserUtils.getSysUser().getUsername());
			} else {
				attendanceDo.setTenantId(SysUserUtils.getSysUser().getTenantId());
				attendanceDo.setCreateBy(SysUserUtils.getSysUser().getUsername());
				attendanceDo.setCreateTime(DateUtil.now());
			}
			attendanceDo.setLocationId(dormitoryStudentInfo.getLocationId());
			attendanceDo.setStudentId(dormitoryStudentInfo.getStudentId());
			attendanceDo.setStatus(dormitoryStudentInfo.getIsNormal());
			attendanceDos.add(attendanceDo);
		}
		return saveOrUpdateBatch(attendanceDos);
	}

	@Override
	public int updateAttendanceStatus(DormitoryAttendanceVo vo) {
		DormitoryAttendanceDo attendanceDo = new DormitoryAttendanceDo();
		BeanUtils.copyProperties(vo, attendanceDo);
		attendanceDo.setCreateBy(SysUserUtils.getSysUser().getUsername());
		attendanceDo.setTenantId(SysUserUtils.getSysUser().getTenantId());
		attendanceDo.setStatus("1");
		attendanceDo.setAttendanceType(DormitoryTypeEnum.LOCATION.getKey());
		return baseMapper.insert(attendanceDo);
	}

	//	 ================================ new attendance service=========================================

	@Resource
	private BaseSpaceLocationDao baseSpaceLocationDao;

	@Override
	public Map<String, Object> getAttendanceStatsByDay(AttendanceDto query) {
		String tenantId = SysUserUtils.getSysUser().getTenantId();
//		String tenantId = "7";
		int actual = 0;
		int leave = 0;
		int absence = 0;
		//查询某日考勤数据
		List<AttendanceDto> stats = dormitoryAttendanceMapper.getAttendanceStatsByDay(new QueryParam(query.getAttendanceDate(), tenantId));
		if(stats == null){
			return null;
		}

		Iterator<AttendanceDto> it = stats.iterator();
		while(it.hasNext()){
			AttendanceDto item = it.next();
			if(StringUtils.isEmpty(item.getBuildingName())){
				it.remove();
			}
		}

		Map<String,Object> top = new HashMap<>();
		for(AttendanceDto item : stats){
			if(item.getAttendanceStatus().equals("0")){
				absence ++ ;
			}else if(item.getAttendanceStatus().equals("1")){
				actual ++ ;
			}else if(item.getAttendanceStatus().equals("2")){
				leave ++ ;
			}
		}

		top.put("shouldArrive",stats.size());
		top.put("actualArrive",actual);
		top.put("leave",leave);
		top.put("absence",absence);

		//对所有考勤数据进行分组根据楼栋
		Map<String,List<AttendanceDto>> groupStats = stats.stream().collect(Collectors.groupingBy(AttendanceDto::getBuildingName));

		//查询某个宿舍某日的考勤数据
		LambdaQueryWrapper<BaseSpaceLocationVO> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(BaseSpaceLocationVO::getLocationType,"1")
				.eq(BaseSpaceLocationVO::getStatus,"1")
				.eq(BaseSpaceLocationVO::getLocationPid,"0")
				.eq(BaseSpaceLocationVO::getTenantId,tenantId);
		List<BaseSpaceLocationVO> parentDormitory = baseSpaceLocationDao.selectList(wrapper);

		List<Map<String, Object>> classify = new ArrayList<>();
		for(BaseSpaceLocationVO item : parentDormitory){
			Map<String,Object> dormitory = new HashMap<>();

			int subActual = 0;
			int subLeave = 0;
			int subAbsence = 0;

			if(groupStats.get(item.getLocationName()) != null){
				for(AttendanceDto subItem : groupStats.get(item.getLocationName())){
					if(subItem.getAttendanceStatus().equals("0")){
						subAbsence ++ ;
					}else if(subItem.getAttendanceStatus().equals("1")){
						subActual ++ ;
					}else if(subItem.getAttendanceStatus().equals("2")){
						subLeave ++ ;
					}
				}
				dormitory.put("locationId",item.getId());
				dormitory.put("locationName",item.getLocationName());
				dormitory.put("shouldArrive",groupStats.get(item.getLocationName()).size());
				dormitory.put("actualArrive",subActual);
				dormitory.put("leave",subLeave);
				dormitory.put("absence",subAbsence);
				classify.add(dormitory);
			}else {
				continue;
			}
		}

		Map<String, Object> returnMap = new HashMap<>();
		returnMap.put("top",top);
		returnMap.put("classify",classify);
		return returnMap;
	}

	@Override
	public List<Object> getAttendanceStatsByBuildAndDay(AttendanceDto query) {
		String tenantId = SysUserUtils.getSysUser().getTenantId();
//		String tenantId = "7";

		String buildName = query.getBuildingName();
		//获取当天当前租户下所有考勤数据
		List<AttendanceDto> allStats = dormitoryAttendanceMapper.getAttendanceStatsByDay(new QueryParam(query.getAttendanceDate(), tenantId));

		if(allStats == null){
			return null;
		}

		Iterator<AttendanceDto> it = allStats.iterator();
		while(it.hasNext()){
			AttendanceDto item = it.next();
			if(StringUtils.isEmpty(item.getBuildingName())){
				it.remove();
			}
		}

		//获取指定条件的数据集合
		List<AttendanceDto> buildStats = allStats.stream().
				filter(item -> item.getBuildingName().equals(buildName)).collect(Collectors.toList());

		if(buildStats != null && buildStats.size() > 0){
			//根据楼层进行分类，按每个楼层分类考勤数据
			Map<String,List<AttendanceDto>> storeyGroup = buildStats.stream().collect(Collectors.groupingBy(AttendanceDto::getStoreyName));

			//查询当前宿舍的所有楼层
			LambdaQueryWrapper<BaseSpaceLocationVO> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(BaseSpaceLocationVO::getLocationType,"2")
					.eq(BaseSpaceLocationVO::getStatus,"1")
					.eq(BaseSpaceLocationVO::getLocationPid,buildStats.get(0).getBuildingId())
					.eq(BaseSpaceLocationVO::getTenantId,tenantId);
			List<BaseSpaceLocationVO> storeyList = baseSpaceLocationDao.selectList(wrapper);

			//返回的数据
			List<Object> returnList = new ArrayList<>();

			for(BaseSpaceLocationVO storey : storeyList){

				Map<String,Object> classify = new HashMap<>();

				//获取楼层的考勤数据
				List<AttendanceDto> storeyStats = storeyGroup.get(storey.getLocationName());
				//判断当前楼层的数据是否为空
				if(storeyStats != null && storeyStats.size() > 0){
					//按每楼层的宿舍分类
					Map<String, List<AttendanceDto>> roomGroup = storeyStats.stream()
							.collect(Collectors.groupingBy(AttendanceDto::getBedRoomName));

					//楼层统计数据
					List<Map<String,Object>> storeyData = new ArrayList<>();
					//每个宿舍的数据
					Iterator<Map.Entry<String, List<AttendanceDto>>> iterator = roomGroup.entrySet().iterator();
					while (iterator.hasNext()){
						Map.Entry<String, List<AttendanceDto>> next = iterator.next();
						List<AttendanceDto> roomStats = next.getValue();
						int actual = 0;
						int leave = 0;
						int absence = 0;
						for(AttendanceDto subItem : roomStats){
							if(subItem.getAttendanceStatus().equals("0")){
								absence ++ ;
							}else if(subItem.getAttendanceStatus().equals("1")){
								actual ++ ;
							}else if(subItem.getAttendanceStatus().equals("2")){
								leave ++ ;
							}
						}
						Map<String, Object> roomData = new HashMap<>();
						roomData.put("locationId",roomStats.get(0).getBedRoomId());
						roomData.put("locationName",next.getKey());
						roomData.put("shouldArrive",roomStats.size());
						roomData.put("actualArrive",actual);
						roomData.put("leave",leave);
						roomData.put("absence",absence);
						storeyData.add(roomData);
//						System.out.println("1");
					}

					Collections.sort(storeyData, new Comparator<Map<String, Object>>() {
						@Override
						public int compare(Map<String, Object> o1, Map<String, Object> o2) {
							return o1.get("locationName").toString().compareTo(o2.get("locationName").toString());
						}
					});

					classify.put("storey",query.getBuildingName() + "-" + storey.getLocationName());
					classify.put("storeyData",storeyData);
				}
				if(classify != null){
					returnList.add(classify);
				}
			}
			return returnList;
		}
		return null;
	}

	@Override
	public List<StudentAttendanceVO> getAttendanceStatsByLocationAndDay(AttendanceDto query) {
		String tenantId = SysUserUtils.getSysUser().getTenantId();
//		String tenantId = "7";
		List<StudentAttendanceVO> list = dormitoryAttendanceMapper
				.getRoomAttendanceDetails(tenantId,query.getBedRoomId(),query.getAttendanceDate());
		return list;
	}

	@Override
	public int updateAttendance(StudentAttendanceVO dto) {
		DormitoryAttendanceDo dormitoryAttendanceDo = new DormitoryAttendanceDo();
		dormitoryAttendanceDo.setId(dto.getAttendanceId());
		dormitoryAttendanceDo.setStatus(dto.getAttendanceStatus());
		return dormitoryAttendanceMapper.updateById(dormitoryAttendanceDo);
	}

	@Override
	public boolean updateAttendanceStatusBatch(List<StudentAttendanceVO> list) {
		for(StudentAttendanceVO item : list){
			if("0".equals(item.getAttendanceStatus())){
				DormitoryAttendanceDo dormitoryAttendanceDo = new DormitoryAttendanceDo();
				dormitoryAttendanceDo.setId(item.getAttendanceId());
				dormitoryAttendanceDo.setStatus("1");
				dormitoryAttendanceMapper.updateById(dormitoryAttendanceDo);
			}
		}
		return true;
	}


	@Override
	public IPage<StudentAttendanceVO> getStudentAttendanceList(Map<String,String> query) {
		String attendanceDate = query.get("attendanceDate");
		String levelName = query.get("levelName");
		String tenantId = SysUserUtils.getSysUser().getTenantId();
		String status = query.get("status");
		Integer pageNum = Integer.valueOf(query.get("pageNum"));
		Integer pageSize = Integer.valueOf(query.get("pageSize"));
		Integer startNum = (pageNum - 1) * pageSize;

		int count = dormitoryAttendanceMapper.getStudentAttendanceListCount(attendanceDate, levelName, tenantId,status);
		List<StudentAttendanceVO> list = dormitoryAttendanceMapper
				.getStudentAttendanceList(attendanceDate, levelName, tenantId,status,startNum,pageSize);
		IPage<StudentAttendanceVO> page = new Page<>();
		page.setTotal(count);
		page.setRecords(list);
		return page;
	}
}
